
package com.gcloud.controller.slb.provider.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.gcloud.controller.ResourceStates;
import org.openstack4j.api.Builders;
import org.openstack4j.model.network.ext.LbPoolV2;
import org.openstack4j.model.network.ext.ListenerProtocol;
import org.openstack4j.model.network.ext.ListenerV2;
import org.openstack4j.model.network.ext.LoadBalancerV2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.gcloud.common.util.StringUtils;
import com.gcloud.controller.provider.NeutronProviderProxy;
import com.gcloud.controller.slb.async.CheckNeutronCreateloadBalancerAsync;
import com.gcloud.controller.slb.dao.LoadBalancerDao;
import com.gcloud.controller.slb.entity.LoadBalancer;
import com.gcloud.controller.slb.model.DescribeLoadBalancerAttributeResponse;
import com.gcloud.controller.slb.model.DescribeLoadBalancerHTTPListenerAttributeResponse;
import com.gcloud.controller.slb.model.DescribeLoadBalancerHTTPSListenerAttributeResponse;
import com.gcloud.controller.slb.model.DescribeLoadBalancerTCPListenerAttributeResponse;
import com.gcloud.controller.slb.model.DescribeLoadBalancersParams;
import com.gcloud.controller.slb.model.DescribeSchedulerAttributeResponse;
import com.gcloud.controller.slb.provider.ILoadBalancerProvider;
import com.gcloud.core.exception.GCloudException;
import com.gcloud.core.simpleflow.Flow;
import com.gcloud.core.simpleflow.FlowDoneHandler;
import com.gcloud.core.simpleflow.NoRollbackFlow;
import com.gcloud.core.simpleflow.SimpleFlowChain;
import com.gcloud.header.api.model.CurrentUser;
import com.gcloud.header.enums.ProviderType;
import com.gcloud.header.enums.ResourceType;
import com.gcloud.header.slb.msg.api.ApiCreateLoadBalancerHTTPListenerReplyMsg;
import com.gcloud.header.slb.msg.api.CreateLoadBalancerReplyMsg;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class NeutronLoadBalancerProvider implements ILoadBalancerProvider {

    @Autowired
    private NeutronProviderProxy neutronProviderProxy;

    @Autowired
    private LoadBalancerDao lberDao;

    @Override
    public ResourceType resourceType() {
        return ResourceType.SLB;
    }

    @Override
    public ProviderType providerType() {
        return ProviderType.NEUTRON;
    }

    @Override
    public CreateLoadBalancerReplyMsg createLb(String loadBalancerName, String vSwitchId, String regionId, CurrentUser currentUser) {
        SimpleFlowChain<org.openstack4j.model.network.ext.LoadBalancerV2, String> chain = new SimpleFlowChain<>("create lb");
        chain.then(new Flow<org.openstack4j.model.network.ext.LoadBalancerV2>("create lb", true) {

            @Override
            public void run(SimpleFlowChain chain, LoadBalancerV2 data) {
                // TODO Auto-generated method stub
                LoadBalancerV2 lb = neutronProviderProxy.createloadBalancer(loadBalancerName, vSwitchId);
                chain.data(lb);
                chain.next();
            }

            @Override
            public void rollback(SimpleFlowChain chain, LoadBalancerV2 data) {
                // TODO Auto-generated method stub
                log.debug("now roll  back");
                neutronProviderProxy.deleteLoadBalancer(data.getId());

            }

        }).then(new NoRollbackFlow<org.openstack4j.model.network.ext.LoadBalancerV2>("save db") {

            @Override
            public void run(SimpleFlowChain chain, LoadBalancerV2 data) {
                // TODO Auto-generated method stub
                LoadBalancer lber = new LoadBalancer();
                lber.setId(UUID.randomUUID().toString());
                lber.setVswitchId(data.getVipSubnetId());
                lber.setName(data.getName());
                Date now = new Date();
                lber.setCreateTime(now);
                lber.setUpdatedAt(now);
                lber.setStatus(data.getProvisioningStatus().name());
                if (regionId == null) {
                    lber.setRegionId("default");
                }
                else {
                    lber.setRegionId(regionId);
                }
                lber.setProvider(providerType().getValue());
                lber.setProviderRefId(data.getId());
                lber.setTenantId(currentUser.getDefaultTenant());
                lber.setUserId(currentUser.getId());
                lberDao.save(lber);
                chain.next();
            }

        }).done(new FlowDoneHandler<org.openstack4j.model.network.ext.LoadBalancerV2>() {

            @Override
            public void handle(LoadBalancerV2 data) {
                // TODO Auto-generated method stub
                chain.setResult(data.getVipAddress());
                CheckNeutronCreateloadBalancerAsync checkAsync = new CheckNeutronCreateloadBalancerAsync();
                checkAsync.setLoadBalancerId(chain.data().getId());
                checkAsync.start();

            }

        }).start();
        if (StringUtils.isNotBlank(chain.getErrorCode())) {
            log.debug("create lb error");
            throw new GCloudException(chain.getErrorCode());
        }

        CreateLoadBalancerReplyMsg reply = new CreateLoadBalancerReplyMsg();
        reply.setAddress(chain.data().getVipAddress());
        reply.setLoadBalancerId(chain.data().getId());
        return reply;
    }
    
    @Override
    public void updateBalancerName(String loadBalancerId, String loadBalancerName) {
        neutronProviderProxy.updateBalancerName(loadBalancerId, loadBalancerName);
    }
    
    @Override
    public void deleteLoadBalancer(String loadBalancerId) {
        neutronProviderProxy.deleteLoadBalancer(loadBalancerId);
    }

        @Override
    public List<LoadBalancer> list(Map<String, String> filters) {
        List<org.openstack4j.model.network.ext.LoadBalancerV2> lbs = neutronProviderProxy.listLoadBalancer(filters);
        List<LoadBalancer> lbList = new ArrayList<>();

        for (org.openstack4j.model.network.ext.LoadBalancerV2 l : lbs) {
            LoadBalancer lb = new LoadBalancer();

            // TODO: set more item ?
            lb.setUpdatedAt(l.getUpdatedAt());
            lb.setName(l.getName());
            lb.setStatus(ResourceStates.status(ResourceType.SLB, ProviderType.NEUTRON, l.getOperatingStatus().name()));
            lb.setId(l.getId());

            lbList.add(lb);
        }

        return lbList;
    }

	@Override
	public DescribeLoadBalancerAttributeResponse describeLoadBalancerAttribute(String loadBalancerId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public DescribeLoadBalancersParams describeLoadBalancers(List<String> loadBalancers) {
		// TODO Auto-generated method stub
		return null;
	}
}
